#include "utils/convert.hpp"

namespace cas::convert
{
    uint64_t dataSizeToSizeType(const std::string &str)
    {
        if (str.empty())
        {
            SFATAL_ERROR_CONT(__func__ << " empty string!");
            return 0;
        }
        size_t len = str.size();
        uint64_t base = 1024;
        uint64_t unit = 1;
        if (str[len - 1] == 'i')
        {
            if (len <= 1)
            {
                SFATAL_ERROR_CONT(__func__ << " invalid string '" << str << '\'');
                return 0;
            }
            len--;
            base = 1000; // Ki Mi ...
        }
        if (str[len - 1] < '0' || str[len - 1] > '9')
        {
            // K M ...
            if (len <= 1)
            {
                SFATAL_ERROR_CONT(__func__ << " invalid string '" << str << '\'');
                return 0;
            }
            switch (str[--len])
            {
            case 'G':
                unit = base * base * base;
                break;
            case 'K':
            case 'k':
                unit = base;
                break;
            case 'M':
                unit = base * base;
                break;
            case 'T':
                unit = base * base * base * base;
                break;
            default:
                SFATAL_ERROR_CONT(__func__ << " invalid suffix of '" << str << '\'');
            }
        }
        // auto-detected base
        return std::stoull(str.substr(0, len), nullptr, 0) * unit;
    }

    bool tomlDataSizeToSizeType(uint64_t &result, const toml::value &val)
    {
        if (val.is_string())
        {
            result = dataSizeToSizeType(val.as_string());
        }
        else if (val.is_integer())
        {
            result = val.as_integer();
        }
        else if (val.is_floating())
        {
            result = static_cast<uint64_t>(val.as_floating());
        }
        else
        {
            SFATAL_ERROR_CONT(__func__ << " invalid toml '" << val << '\'');
            return false;
        }
        return true;
    }

    template <typename T>
    bool tomlDataSizeToSizeType(T &result, const toml::value &val)
    {
        uint64_t tmp;
        bool ret = tomlDataSizeToSizeType(tmp, val);
        result = (T)tmp;
        return ret;
    }

    // @important explicit instantiation for tomlDataSizeToSizeType
    template bool tomlDataSizeToSizeType<uint64_t>(uint64_t &result, const toml::value &val);
    template bool tomlDataSizeToSizeType<int64_t>(int64_t &result, const toml::value &val);
    template bool tomlDataSizeToSizeType<uint32_t>(uint32_t &result, const toml::value &val);
} // namespace cas
